cmake_minimum_required(VERSION 3.15)
########################################################################################################
# Function to find a library given its name and type (STATIC, SHARED, or HEADER_ONLY)
function(find_custom_library)
  # parse the arguments
  set(options "RESET_FOUND") # 添加RESET_FOUND作为可选项
  set(oneValueArgs LIB_NAME LIB_TYPE USR_DIR SYSTEM_DEPEND)
  set(multiValueArgs  SEARCH_OPTIONS ADDITIONAL_LIBS)
  cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  # Initialize variable for additional libraries found
  string(TOUPPER ${ARG_LIB_NAME} LIB_NAME_UPPER)
  if(ARG_RESET_FOUND OR NOT DEFINED ${LIB_NAME_UPPER}_FOUND)
    set(${LIB_NAME_UPPER}_FOUND FALSE CACHE BOOL "${ARG_LIB_NAME} found" FORCE)
  endif()

  # 首先检查库是否已经被找到
  if(NOT ${LIB_NAME_UPPER}_FOUND)

  # 检查并处理互斥的搜索选项
  set(SEARCH_OPTIONS_PROVIDED FALSE)
  foreach(option IN LISTS ARG_SEARCH_OPTIONS)
    if(";NO_CMAKE_ENVIRONMENT_PATH;NO_CMAKE_PATH;NO_SYSTEM_ENVIRONMENT_PATH;NO_CMAKE_SYSTEM_PATH;" MATCHES ";${option};")
      if(SEARCH_OPTIONS_PROVIDED)
        # 发现互斥的搜索选项，发出警告并忽略后面的选项
        message(WARNING "Ignoring mutually exclusive search option: ${option} because another search option has already been specified.")
      else()
        list(APPEND SEARCH_OPTIONS_LIST ${option})
        set(SEARCH_OPTIONS_PROVIDED TRUE)
      endif()
    else()
      message(WARNING "Invalid search option: ${option}")
    endif()
  endforeach()
  # 如果没有提供特定的搜索选项，则默认使用 NO_DEFAULT_PATH
  if(NOT SPECIFIC_OPTIONS_PROVIDED)
    list(APPEND SEARCH_OPTIONS_LIST NO_DEFAULT_PATH)
  endif()

  # use different base path for different platforms
  if(COMPILER_SYSTEM_WINDOWS)
    set(BASE_LIB_PATH ${CMAKE_SOURCE_DIR}/third_party/win64)
  elseif(COMPILER_SYSTEM_LINUX)
    if(COMPILER_ARCH_AARCH64)
      set(BASE_LIB_PATH ${CMAKE_SOURCE_DIR}/third_party/aarch64)
    elseif(COMPILER_ARCH_ARM32)
      set(BASE_LIB_PATH ${CMAKE_SOURCE_DIR}/third_party/arm32)
    elseif(COMPILER_ARCH_X86_64)
      set(BASE_LIB_PATH ${CMAKE_SOURCE_DIR}/third_party/linux_x86)
    else()
      set(BASE_LIB_PATH ${CMAKE_SOURCE_DIR}/third_party/x86)
    endif()
  endif()

  # check if a custom path was provided
  if(ARG_USR_DIR)
    set(LIB_PATH "${BASE_LIB_PATH}/${ARG_USR_DIR}" CACHE PATH "${ARG_USR_DIR} path" FORCE)
  else()
    set(LIB_PATH "${BASE_LIB_PATH}/${ARG_LIB_NAME}" CACHE PATH "${ARG_LIB_NAME} path" FORCE)
  endif()

  # Check if it's a header-only library
  if(${ARG_LIB_TYPE} STREQUAL "HEADER_ONLY")
    # Set include path
    set(${LIB_NAME_UPPER}_INCLUDE_DIRS ${LIB_PATH} CACHE PATH "${ARG_LIB_NAME} include directories" FORCE)
    file(GLOB HEADER_FILES "${LIB_PATH}/*.h" "${LIB_PATH}/*.hpp")
    if(HEADER_FILES)
      set(${LIB_NAME_UPPER}_FOUND TRUE CACHE BOOL "${ARG_LIB_NAME} found" FORCE)
    endif()
  else()
    # Set include path
    set(${LIB_NAME_UPPER}_INCLUDE_DIRS ${LIB_PATH}/include CACHE PATH "${ARG_LIB_NAME} include directories" FORCE)
    # Handle STATIC or SHARED libraries
      # Handle STATIC or SHARED libraries

      #判断参数个数
      set(ARGUMENTS ${ARG_LIB_NAME} ${ARG_ADDITIONAL_LIBS})
      list(LENGTH ARGUMENTS ARGUMENTS_LENGTH)
      message("The total number of arguments is: ${ARGUMENTS_LENGTH}")

      foreach(LIB ${ARG_LIB_NAME} ${ARG_ADDITIONAL_LIBS})
        string(SUBSTRING ${ARG_LIB_NAME} 0 3 LIB_NAME_PREFIX)
        if(${ARG_LIB_TYPE} STREQUAL "STATIC")
            if(NOT ${LIB_NAME_PREFIX} STREQUAL "lib")
              set(LIB_FULL_NAME "lib${LIB}.a")
            else()  
              set(LIB_FULL_NAME "${LIB}.a")
            endif()
        elseif(${ARG_LIB_TYPE} STREQUAL "SHARED")
            if(${LIB_NAME_PREFIX} STREQUAL "lib")
              set(LIB_FULL_NAME "${LIB}.so")
            else()  
              set(LIB_FULL_NAME "${LIB}")
            endif()
        endif()
        unset(FOUND_LIB CACHE)
        find_library(FOUND_LIB NAMES ${LIB_FULL_NAME} PATHS ${LIB_PATH}/lib ${SEARCH_OPTIONS_LIST})

        if(FOUND_LIB)
          list(FIND ${LIB_NAME_UPPER}_LIBRARIES ${FOUND_LIB} _index)
          if(_index EQUAL -1) # 如果找不到，_index将等于-1
            list(APPEND ${LIB_NAME_UPPER}_LIBRARIES ${FOUND_LIB})
          endif()
          set(${LIB_NAME_UPPER}_FOUND TRUE CACHE BOOL "${ARG_LIB_NAME} found" FORCE)
        endif()
      endforeach()
      # 将列表转换为以空格分隔的字符串
      string(REPLACE ";" " " _temp_string "${${LIB_NAME_UPPER}_LIBRARIES}")
      # 将字符串存储回缓存
      set(${LIB_NAME_UPPER}_LIBRARIES "${_temp_string}" CACHE STRING "Libraries for ${LIB_NAME_UPPER}" FORCE)
    endif()  
  endif()
  message(STATUS "Looking for ${ARG_LIB_NAME} - ${ARG_LIB_TYPE} - ${FOUND_LIB}")
  message(STATUS "  Path: ${LIB_PATH} - ${SEARCH_OPTIONS_LIST}")
  message(STATUS "  Include dirs: ${${LIB_NAME_UPPER}_INCLUDE_DIRS}")
  message(STATUS "  Libraries: ${${LIB_NAME_UPPER}_LIBRARIES}")

  # Set the _FOUND variable to TRUE if the library and all additional libraries were found
  if(${LIB_NAME_UPPER}_FOUND)
    message(STATUS "############# Search task executed successfully #############")
  else()  
    message(STATUS "############# Search task execution failed #############")
  endif()
  message("\n\n\n")
endfunction()
########################################################################################################
macro(target_include_link_lib TARGET LIB_NAME)
  string(TOUPPER ${LIB_NAME} LIB_NAME_UPPER)
  message(STATUS "link for library: ${LIB_NAME}")
  
  # 检查库是否被成功找到
  if(${LIB_NAME_UPPER}_FOUND)
    message(STATUS "Library ${LIB_NAME} found.")
    # 显式读取变量并增加调试
    set(LOCAL_INCLUDE_DIRS ${${LIB_NAME_UPPER}_INCLUDE_DIRS})
    # 包含头文件目录
    if(DEFINED LOCAL_INCLUDE_DIRS AND NOT LOCAL_INCLUDE_DIRS STREQUAL "")
      target_include_directories(${TARGET} PUBLIC ${LOCAL_INCLUDE_DIRS})
    else()
    endif()
    message(STATUS "Target ${TARGET} include dirs: ${${LIB_NAME_UPPER}_INCLUDE_DIRS}")

    # 如果不是仅头文件库，则链接它
    if(NOT ${LIB_NAME_UPPER}_LIBRARIES STREQUAL "")
      target_link_libraries(${TARGET} PUBLIC ${${LIB_NAME_UPPER}_LIBRARIES})
    endif()
  else()
    message(FATAL_ERROR "Library ${LIB_NAME} not found. Please ensure it is installed and findable.")
  endif()
endmacro()
########################################################################################################
# 处理库列表的宏
# 定义 include_and_link_libs 宏
macro(target_include_link_libs TARGET)
  set(LIBS_LIST ${ARGN}) # ARGN 变量包含了除了 TARGET 之外的所有参数
  message(STATUS "Starting to include and link libraries for target: ${TARGET}")
  foreach(LIB IN LISTS LIBS_LIST)
    include_and_link_lib(${TARGET} ${LIB})
  endforeach()
  message(STATUS "Finished including and linking libraries for target: ${TARGET}")
endmacro()
